package ngat.oss;

import ngat.phase2.*;
import ngat.phase2.nonpersist.*;

import java.io.*;
import java.util.*;

import jyd.dbms.*;
import jyd.storable.*;
import jyd.collection.*;


/** Contains methods for accessing the OSS Phase2 database, used by TransactionRequests
 * to locate DBObjects by their Path names. */
public class OSS_Utilities {

    /** Set true if caching is required.*/
    protected static boolean useCache;

    /** True if the OSS_Util is initialized.*/
    protected static boolean initialized;

    protected static HashMap cache;

    public static File databaseDir = null;
    
    public static void setDatabaseDir(File in) { databaseDir = in;}

    public static String rootName = null;

    /** Initialize. Set cached True if the DB should be in-memory cached.*/
    public static void init(boolean cached) { 
	// Run once only.
	if (initialized) return;

	useCache = cached;
	// Now load the cache..
	cache = new HashMap();
	/** Loads the Proposals into cache.*/
	if (useCache) {
	   Root     root     = null;	    
	   Tag      tag      = null;	    
	   User     user     = null;	    
	   Proposal proposal = null;
	   
	   root = fetchRoot();
	   
	   Iterator iTag = root.listAllTags();
	   while (iTag.hasNext()) {
	       
	       tag = (Tag)iTag.next();
	       
	       Iterator iUser = tag.listAllUsers();
	       while (iUser.hasNext()) {
		   
		   user = (User)iUser.next();
		   
		   Iterator iProp = user.listAllProposals();
		   while (iProp.hasNext()) {
		       
		       KVPair pair = (KVPair)iProp.next();
		       String name = (String)pair.getKey();
		       Path   path = new Path(user.getFullPath(), name);
		       //System.err.println("OS_U::Trying to cache Proposal for Path: "+path.toString());
		       try {
			   proposal = fetchProposal(path);
			   //System.err.println("OS_U::Proposal: "+path.toString()+" Loaded OK....");
			   cache.put(path.toString(), proposal);
			   //System.err.println("OS_U::Proposal: "+path.toString()+" Cached OK....");
		       } catch (IOException iox) {
			   System.err.println("OS_U::Proposal: "+path.toString()+
					      " ** Error fetching from Database: "+iox);	
			   continue;
		       }		
		       
		   }
	       }
	   }
	}
	initialized = true;
    }

    public static void setRootName(String in) { rootName = in; }
   
    public static Root fetchRoot() {
	System.err.println("OSSU: Looking for root:"+rootName);
	return fetchRoot(new Path(rootName));
    }

    public static Root fetchRoot(Path path) {
	//System.err.println("OSSU::FindRoot using:["+path+"]");
	if (path.getRootByName() == null) return null;
	Transaction trans = Transaction.current();	
	trans.abort();
	Map         rootMap   = trans.parent().root();
	//System.err.println("OS_U::fetchRoot::Got:"+rootMap);
	if (rootMap == null) return null;
	//System.err.println("Entries");
	//Iterator it = rootMap.keySet().iterator();
	//while (it.hasNext()){System.err.println(">"+it.next());}
	//SortedMap   rootEntry = (SortedMap)rootMap.get("ROOT");
	//if (rootEntry == null) return null;
	//Root        root      = (Root)rootEntry.get(path.getRootByName());
	//System.err.println("OS_U::fetchRoot::Looking in rootmap for entry:"+path.getRootByName());
	Root        root      = (Root)rootMap.get(path.getRootByName());
	return root;
    }
    
    public static Tag fetchTag(Path path) {
	//System.err.println("OSSU::FindTag using:["+path+"]");
	if (path.getTagByName() != null && fetchRoot(path) != null) {
	    Tag tag = fetchRoot(path).findTag(path.getTagByName());
	    if (tag != null) return tag;
	}
	return null; 
    }
    
    public static User fetchUser(Path path) {
	//System.err.println("OSSU::FindUser using:["+path+"]");
	if (path.getUserByName() != null && fetchTag(path) != null) {
	    User user = fetchTag(path).findUser(path.getUserByName());
	    if (user != null) {
		//System.err.println("OSS_U:: fU: Found and About to return: "+user);
		return user;
	    }
	}
	return null;   
    }
    
    public static Proposal fetchProposal(Path path) throws IOException {  
	  Proposal proposal = null;
	  // Make sure we dont try to fetch from cache before its built...
	  if (useCache && initialized) {
	      // Get just the Proposal part of the Path.
	      String pp = "/"+
		  path.getRootByName() + "/"+
		  path.getTagByName()  + "/"+
		  path.getUserByName() + "/"+
		  path.getProposalByName(); 
	      //System.err.println("OS_U:Attempting decache for Path: "+pp.toString());
	      proposal = (Proposal)cache.get(pp);
	      if (proposal != null)
		  //System.err.println("OS_U::Decached Proposal: "+proposal.getFullPath());
	      return proposal;
	  } else {
	      if (path.getProposalByName() != null && fetchUser(path) != null) {

		  User user = fetchUser(path);
		  
		  String name = (String)user.findProposal(path.getProposalByName());

		  String tname = path.getTagByName().replace('.', '-');
		  String uname = path.getUserByName().replace('.', '-');
		  
		  String filename = tname + "-"+ uname+ "-"+ path.getProposalByName(); 		  
		  
		  File file = new File(databaseDir, "store/"+filename);	
		
		  ObjectInputStream fin = new ObjectInputStream(new FileInputStream(file));	
		  long s1 = System.currentTimeMillis();
		  
		  try {
		      proposal = (Proposal)fin.readObject();
		      //		      System.err.println("OSS_U::Read proposal back from: "+file.getPath());
		      fin.close();		   
		      fin = null;
		      file= null;
		  } catch (ClassNotFoundException cx) {		     
		      System.err.println("OSS_U::While Reading proposal from:"+file+" : "+cx); 
		      proposal = null;
		  } catch (Exception e) {		     
		      System.err.println("OSS_Utilities::While Reading proposal from:"+file+" : "+e); 
		      proposal = null;
		      
		  }
		  long s2 = System.currentTimeMillis();
		  //System.err.println("OS_U:: read proposal from file: "+
		  //  	     " in "+(s2 -s1)+" millis");
		  if (proposal != null) return proposal;	    
	      }
	  }
	  return null;
    } 

   
    /** Store the Proposal to the DB file. If caching then we save the Proposal inmemory also.*/   
    public static void storeProposal(Proposal proposal) throws IOException {
	
	if (proposal == null)
	    throw new IOException("Proposal is null - cannot store");
	
	Path path = new Path(proposal.getFullPath());
	
	String tname = path.getTagByName().replace('.', '-');
	String uname = path.getUserByName().replace('.', '-');
	
	String filename = tname + "-"+ uname+ "-"+ path.getProposalByName(); 
	
	
	File file = new File(databaseDir, "store/"+filename);	

	System.err.println("OSS_U::Proposal: "+proposal.getFullPath()+" -> "+file.getName());

	ObjectOutputStream fout = new ObjectOutputStream(new FileOutputStream(file));
	fout.flush();
	fout.writeObject(proposal);
	fout.flush();
	fout.close();
	
	System.err.println("OSS_U::Saved Proposal to: "+file.getPath());	
	
	if (useCache) {
	  cache.put(proposal.getFullPath(), proposal);
	    System.err.println("OSS_U::Cached Proposal: "+proposal.getFullPath());
	}
    }

    public static void eraseProposal(Proposal proposal) throws IOException {
	
	if (proposal == null)
	    throw new IOException("Proposal is null - cannot store");
	
	Path path = new Path(proposal.getFullPath());
	
	String tname = path.getTagByName().replace('.', '-');
	String uname = path.getUserByName().replace('.', '-');
	
	String filename = tname + "-"+ uname+ "-"+ path.getProposalByName(); 
	
	
	File file = new File(databaseDir, "store/"+filename);	
	
	if (file.exists())
	    file.delete();

    }
    

}    



















































































